/*
 * Copyright 2015-2016 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
 *
 * You may not use this file except in compliance with the terms and conditions set forth
 * in the accompanying LICENSE.TXT file.
 *
 * THESE MATERIALS ARE PROVIDED ON AN "AS IS" BASIS.  AMAZON SPECIFICALLY DISCLAIMS, WITH
 * RESPECT TO THESE MATERIALS, ALL WARRANTIES, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
 */
package com.amazon.alexa.voicechrome.internal.views.util.wave;

import android.content.Context;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.ColorUtils;

import com.amazon.alexa.voicechrome.R;

public class AmplitudePainter {

    public final Paint amplitudeGlowPaint;
    public final Paint amplitudePaintBase;
    private final int defaultColor;
    private final float[] radialStops;
    private final int[] radialColors;
    private final int[] linearTopColors;
    private final float[] linearTopStops;
    private final int[] linearBaseColors;
    private final float[] linearBaseStops;
    private final Paint topGradientPaint;
    private static final float GRADIENT_SCREEN_WIDTH_RATIO = .4f;

    AmplitudePainter(Context context) {
        defaultColor = ContextCompat.getColor(context, R.color.voicechrome_amplitude_view_color);
        amplitudeGlowPaint = new Paint();
        amplitudeGlowPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        amplitudeGlowPaint.setAntiAlias(true);
        amplitudeGlowPaint.setColor(defaultColor);
        amplitudeGlowPaint.setStrokeWidth(1);
        amplitudeGlowPaint.setStrokeJoin(Paint.Join.BEVEL);
        amplitudeGlowPaint.setStrokeCap(Paint.Cap.BUTT);

        amplitudePaintBase = new Paint(amplitudeGlowPaint);

        radialColors = new int[]{getColorWithTransparency(defaultColor, .7), getColorWithTransparency(defaultColor, 0)};
        radialStops = new float[]{0f, .7f, .75f, .8f};

        linearTopColors = new int[]{getColorWithTransparency(defaultColor, .4), getColorWithTransparency(defaultColor, 0)};
        linearTopStops = new float[]{0f, .2f, .5f, .6f, .7f, .8f};

        linearBaseColors = new int[]{getColorWithTransparency(defaultColor, 0), getColorWithTransparency(defaultColor, .8), defaultColor, getColorWithTransparency(defaultColor, .8), getColorWithTransparency(defaultColor, 0)};
        linearBaseStops = new float[]{.2f, .5f, .80f};

        topGradientPaint = new Paint();
        topGradientPaint.set(amplitudeGlowPaint);
    }

    private int getColorWithTransparency(int defaultColor, double percent) {
        return ColorUtils.setAlphaComponent(defaultColor, percentToDecimal(percent));
    }

    private int percentToDecimal(double percent) {
        return (int) Math.round(percent * 255);
    }

    /**
     * Two gradients are created with the provided dimensions: a radial gradient from the middle
     * out to some percentage of the screen (defined by GRADIENT_SCREEN_WIDTH_RATIO) and a linear bottom-up gradient
     * to make the radial gradient fade out at the top at the correct rate.
     *
     * @param viewWidth the full width of the gradient
     * @param viewHeight the full height of the gradient
     */
    public void updatePaintShadersForSize(int viewWidth, int viewHeight) {
        // Create a gradient to mask the radial gradient from the top down
        LinearGradient topGradientShader = new LinearGradient(0, viewHeight, 0, 0, linearTopColors, null, Shader.TileMode.CLAMP);
        topGradientPaint.setShader(topGradientShader);
        // Create the main radial gradient for the amplitude visual
        // CenterY is shifted down to get the widest parts of the circle closer the line, rather than having an halo effect over the progress bar
        RadialGradient radialGradientShader = new RadialGradient(viewWidth/2, viewHeight - viewHeight/3, viewWidth * GRADIENT_SCREEN_WIDTH_RATIO, radialColors, null, Shader.TileMode.CLAMP);
        // Merge the 2 gradients and set the new merged gradient on the pain
        ComposeShader merged = new ComposeShader(topGradientShader, radialGradientShader, new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
        amplitudeGlowPaint.setShader(merged);

        // Create a gradient to go left-to-right and fade out on the edges
        // This will be painted in the middle of the amplitude view and provide to main visual feedback
        LinearGradient linearGradient = new LinearGradient((int)(viewWidth * .2),
                0,
                viewWidth - (int)(viewWidth * .2),
                viewHeight,
                linearBaseColors, null,
                Shader.TileMode.CLAMP);

        amplitudePaintBase.setShader(linearGradient);
    }
}
